refactor: move project manager to service layer#68
Conversation
Greptile SummaryThis PR moves project management from a process-local
Confidence Score: 4/5Safe to merge after regenerating the sqlc output — the SQL source is correct but the compiled constant for ArchiveProject is one generation behind. The service logic, archived-row filtering, and re-add-after-remove flow are all correct. The one concrete defect is the archiveProject constant in gen/projects.sql.go: the SQL source was patched with AND archived_at IS NULL but sqlc generate was not re-run for that query, so a second DELETE on the same project still returns 200 OK at runtime. Everything else — the domain type, store interface, controller wiring, and test coverage — looks sound. backend/internal/storage/sqlite/gen/projects.sql.go — the archiveProject constant needs to be regenerated to pick up the AND archived_at IS NULL guard that is already present in projects.sql. Important Files Changed
Sequence DiagramsequenceDiagram
participant C as HTTP Controller
participant S as service/project.Service
participant ST as sqlite Store
participant DB as SQLite DB
Note over C,DB: Add project
C->>S: Add(ctx, AddInput)
S->>ST: FindProjectByPath(path)
ST->>DB: "SELECT WHERE path=? AND archived_at IS NULL"
DB-->>ST: ErrNoRows
ST-->>S: "ok=false"
S->>ST: GetProject(id)
ST->>DB: "SELECT WHERE id=?"
DB-->>ST: row, ok
Note over S: if ok and ArchivedAt.IsZero() and path differs, return ID conflict
S->>ST: UpsertProject(record with zero ArchivedAt)
ST->>DB: "INSERT ON CONFLICT DO UPDATE SET archived_at=NULL"
S-->>C: "Project{}"
Note over C,DB: Remove project
C->>S: Remove(ctx, id)
S->>ST: ArchiveProject(id, now)
ST->>DB: "UPDATE SET archived_at=? WHERE id=?"
Note over DB: Missing AND archived_at IS NULL in gen file
DB-->>ST: "rowsAffected=1 even if already archived"
ST-->>S: "ok=true"
S-->>C: RemoveResult 200 OK
Note over C,DB: Get project
C->>S: Get(ctx, id)
S->>ST: GetProject(id)
ST->>DB: "SELECT WHERE id=?"
DB-->>ST: row, ok
Note over S: if not ok or not ArchivedAt.IsZero() return PROJECT_NOT_FOUND
S-->>C: "GetResult{Status:ok, Project}"
Reviews (8): Last reviewed commit: "refactor: move pr manager into service l..." | Re-trigger Greptile |
|
go test ./... is currently failing on PR 68 in backend/internal/httpd/apispec/specgen: the drift test says the embedded backend/internal/httpd/apispec/openapi.yaml is stale compared with fresh specgen.Build() output. I confirmed that running go generate ./... from the backend/ directory regenerates the spec and makes go test ./internal/httpd/apispec/specgen pass, so the fix is to regenerate and commit openapi.yaml. Since this surfaced on a Windows checkout, it may also be worth adding a .gitattributes rule such as backend/internal/httpd/apispec/openapi.yaml text eol=lf, or normalizing line endings in the test, so the byte-for-byte drift check does not fail across Windows/Linux checkouts |
…ory store The project Manager now runs only against the durable backend store: remove the process-local MemoryStore (and NewMemoryManager), and require a real Store. The daemon already wires the sqlite store; tests now build a real temp-dir sqlite store instead of the mock. - Move Row + the Store port to project/store.go. The Store interface stays because it is the dependency-inversion port that lets the manager reach the backend without an import cycle (storage imports project.Row), not an extra mock layer — there is no longer any in-memory implementation. - NewManager requires a non-nil Store (no in-memory fallback). - Add project/manager_test.go: List/Add/Get/Remove happy paths + PATH_REQUIRED/NOT_A_GIT_REPO/PATH_ALREADY_REGISTERED/ID_ALREADY_REGISTERED, PROJECT_NOT_FOUND/INVALID_PROJECT_ID, and UpdateConfig — all against a real sqlite store (the service-logic tests #47 lacked). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…penAPI
- Remove POST /reload, PATCH /{id}, POST /{id}/repair routes and their
Manager methods (Reload, UpdateConfig, Repair) and DTOs (ReloadResult,
UpdateConfigInput) — not needed at this stage
- Merge Manager interface into manager.go; delete project.go (single-impl
split served no purpose)
- Remove dead notImplemented helper from errors.go
- Port PR #59 code-first OpenAPI generation: controllers/dto.go named
response types, specgen/build.go (4 routes), parity + drift tests,
cmd/genspec, go generate wiring; regenerate openapi.yaml
- Add swaggest deps; add YAML() method to apispec.Spec
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- t.Skipf → t.Fatalf in gitRepo helper: git failures now hard-fail instead of silently skipping manager tests on a misconfigured runner - FindProjectByPath: add AND archived_at IS NULL so archived paths don't permanently block re-registration (update queries/projects.sql and generated gen/projects.sql.go) - Add TestManager_ReaddAfterRemove to lock the fix Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
3358265 to
b940df4
Compare
Re-integrate the agent-adapter layer onto main's rewritten session lane. main (#62/#66/#67/#68/#69) moved the session manager into session_manager plus a service layer, reworked the domain (Activity, IsTerminated), and removed the tmux runtime. This merge: - Keeps the rich, hooks-capable ports.Agent (in internal/ports) as the canonical agent contract; session_manager.Manager now resolves a real adapter per session via ports.AgentResolver (from cfg.Harness on Spawn, the stored harness on Restore) and builds RuntimeConfig.Argv. - Drops the tmux runtime; standardizes on zellij. - Re-adds the daemon's per-session agent resolver wiring (buildAgentResolver over the claude-code + codex registry, AO_AGENT default), ready to plug into the httpd session-route slot. go build, go vet, and go test -race are green; the zellij/tmux real integration tests are environment-gated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Rebases the project-manager cleanup onto latest
mainand aligns service code under resource-specific service packages.MemoryStore/NewMemoryManagerbackend/internal/projectintobackend/internal/service/projectbackend/internal/service/sessionbackend/internal/service/prbackend/internal/projectpackage entirelydomain.ProjectRecordas the durable storage row shape shared by service and sqlite without creating service↔storage cyclesListProjects,GetProject,FindProjectByPath,UpsertProject,ArchiveProject)openapi.yamlNotes
The old import-cycle concern is handled by putting the persistence row in
domainand the service-facing store interface inservice/project; sqlite implements that interface implicitly.service/projectdoes not import sqlite, and sqlite does not importservice/project.Testing
npm run lint